<?php

namespace bee;
/*
define("GRID_DATASOURCE_ARRAY",   1);
define("GRID_DATASOURCE_DAO",     2);
define("GRID_FETCH_ALL",          4);
define("GRID_FETCH_PAGED",        8);
define("GRID_FILL_TABLE",         16);
define("GRID_FILL_VARIABLES",     32);
define("GRID_FILL_FILTER",        64);
define("GRID_FILL_ALL",           112);
*/
/**
 *
 * @author dzelenika
 *
 */
class ajaxGrid extends grid implements Isingleton
{ protected static $__instance;
  protected static $__dispatcher;
  protected $__gridID = "201003060345";
  protected $__numRows = 0;
  protected $__foreignKeys;
  protected $foreignKeys;
	protected $state;
	protected $dispatcher;
	protected static $DSDoc;
	public $DAORow;
	public $afterWhere;
	public $not_filter = array("sys_page", "sys_action", "PHPSESSID", "XDEBUG_SESSION", "sys_stateID", "app_back", "username", "__form");//, "grid_step");
	public $fetchType = GRID_FETCH_PAGED;
	public $options;


  static function getInstance($noLoad = true)
  { if(!is_subclass_of(static::$__instance, __CLASS__))//self))
    { if($noLoad)
      { static::$__instance = new static;
        //static::$__dispatcher = dispatcher::getInstance();
        static::$__dispatcher->addObject(static::$__instance);
        static::$__dispatcher->dispatch("createGrid");
      } else
      { if(static::$__instance = factory::load(static::$__gridID))
        { static::$__dispatcher = dispatcher::getInstance();
          static::$__dispatcher->addObject(static::$__instance);
          static::$DSDoc = XMLDataHub::getInstance();
        } else
        { static::$__instance = new static;
          static::$__dispatcher->addObject(static::$__instance);
          static::$__dispatcher->dispatch("createGrid");
        }
      }
      static::$__dispatcher->dispatch("loadGrid");
      //static::dispatchChildren("onLoad");
/*
      static::$dispatcher->dispatch("doEvents");
      if(isset($_REQUEST["sys_action"]))
      { static::$dispatcher->dispatch($_REQUEST["sys_action"]);
      }
*/
      //static::dispatchChildren("onDraw");
      static::$__dispatcher->dispatch("drawGrid");
      //static::dispatchChildren("onUnLoad");
      static::$__dispatcher->dispatch("unloadGrid");
    }
    return static::$__instance;
  }

	function __construct(&$DAORow = null, afterWhere $afterWhere = null, array $foreignKeys = null, array $options = null)
	{ static::$__dispatcher = dispatcher::getInstance();
    static::$DSDoc = XMLDataHub::getInstance();
    //$this->__parent = isset($_REQUEST["__frm_back"]) ? $_REQUEST["__frm_back"] : "";;


	  //return 0;
	  $this->options = $options;
	  $this->__withEvents = true;
	  if(($options & GRID_FETCH_ALL) == GRID_FETCH_ALL)
	  { $this->fetchType = GRID_FETCH_ALL;
	  }	else
	  { $this->fetchType = GRID_FETCH_PAGED;
	  }

		if($DAORow == null)
	  {  $DAORow = array();
	  }
		if(is_array($DAORow))
    { $this->DAORow =       &$DAORow;
    } else
    { $this->DAORow =       $DAORow;
      $this->afterWhere =   ($afterWhere ?: new afterWhere());
    }
		$this->state = 		      new oArray();
	  $this->dispatcher = dispatcher::getInstance();

		$this->dispatcher->addObject($this);
	  $this->dispatcher->dispatch("createGrid");
//    $this->dispatcher->dispatch("processGridEvents");
//    $this->dispatcher->dispatch("drawGrid");
//    $this->dispatcher->dispatch("unloadGrid");

	}

	public function createGrid($evt)
	{

	}
	 /**
   *
   * @param $evt
   * @return void
   */
  public function onUnLoad($evt)
  { //static::$DSDoc->setVariable("__frm_back", $this->__parent);
    //factory::save($this, $this->__gridID);
    ///echo "-unloadGrid-";

  }

   /**
   *
   * @param $evt
   * @return void
   */
  public function _onLoad($evt)
  { //static::$DSDoc->setVariable("__frm_back", $this->__parent);

    //echo "-loadGrid-";

  }

  public function onDraw($evt)
  { //static::$DSDoc->setVariable("__frm_back", $this->__parent);
    //echo "-drawGrid-";
  }


	public function setDataSource($dataDource)
	{ $this->DAORow = $dataDource;
	  $this->__numRows = 0;    ////?????
	  $this->resetGrid();
	}

	public function resetGrid()
	{ $this->state->setField("grid_order_type", "");
    $this->state->setField("grid_order", "");
    $this->state->setField("SQLOrder", "");
    $this->state->setField("grid_order_field", "");
    $this->state->setField("grid_page_no", 0);
	}

	public function setForeignKey($field, array $FKArray)
	{  $this->foreignKeys[$field] = $FKArray;
	}

	public static function getNumRows()
	{ if(is_array($this->DAORow))
	  { return count($this->DAORow);
	  } else if(is_subclass_of($this->DAORow, "bee\\DAO"))
	  { return $this->__numRows;
	  } else
	  { return 0;
	  }
	}

	public function grid_next($evt)
	{ $step = config::getInstance()->app_GRID_STEP;
	  $this->state->setField("grid_page_no", $this->state->getField("grid_page_no") + 1);
     if($this->state->getField("grid_page_no") > ($this->__numRows - 1) / $step) //????????????????????????????????????????? istestirati
     { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)) );//?????????????????????????????????????????
     }
	}

  public function grid_prev($evt)
  { $this->state->setField("grid_page_no", $this->state->getField("grid_page_no") - 1);
    if($this->state->getField("grid_page_no") < 0)
    { $this->state->setField("grid_page_no", 0);
    }
  }

  public function grid_change_order($evt)
  { $this->state->setField("grid_order_type", isset($evt["grid_order_type"]) ? $evt["grid_order_type"] : "text");
    if($evt["grid_change_field"] == $this->state->getField("grid_order_field"))
    { if($this->state->getField("grid_order") == "descending")
      { $this->state->setField("grid_order", "ascending");
        $this->state->setField("SQLOrder", "ASC");
      } else
      { $this->state->setField("grid_order", "descending");
        $this->state->setField("SQLOrder", "DESC");
      }
    } else
    { $this->state->setField("grid_order", "ascending");
      $this->state->setField("SQLOrder", "ASC");
      $this->state->setField("grid_order_field", $evt["grid_change_field"]);
      $this->state->setField("grid_page_no", 0);
    }
  }

  public function grid_set_order($evt)
  {//echo "gso";
     $this->state->setField("grid_order_type", isset($evt["grid_order_type"]) ? $evt["grid_order_type"] : ($this->state->getField("grid_order_type")?: "text"));
    if(($this->state->getField("grid_order_field") == $evt["grid_order_field"]) || isset($evt["ignore_change"]))
    { $this->state->setField("grid_order", $evt["grid_order"]);
    } else
    { $this->state->setField("grid_order", "ascending");
    }

    $this->state->setField("SQLOrder", ($this->state->getField("grid_order") == "descending") ? "DESC" : "ASC");
    $this->state->setField("grid_order_field", $evt["grid_order_field"]);
    $this->state->setField("grid_page_no", 0);
  }

  public function grid_move($evt)
  { $step = config::getInstance()->app_GRID_STEP;
  	$this->state->setField("grid_page_no", $this->state->getField("grid_page_no") + @$evt["grid_step"]);
    if($this->state->getField("grid_page_no") > ($this->__numRows - 1) / $step)
    { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)) );
    }
    if($this->state->getField("grid_page_no") < 0)
    { $this->state->setField("grid_page_no", 0);
    }
  }

  public function grid_goto($evt)
  { $step = config::getInstance()->app_GRID_STEP;
    $this->state->setField("grid_page_no", $evt["page_no"]);
    if($this->state->getField("grid_page_no") > ($this->__numRows - 1) / $step)
    { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)) );
    }
    if($this->state->getField("grid_page_no") < 0)
    { $this->state->setField("grid_page_no", 0);
    }
  }

  public function grid_first($evt)
  { $this->state->setField("grid_page_no", 0);
  }

  public function grid_last($evt)
  { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)));//????
  }
  public function grid_FFWD($evt)
  { $step = config::getInstance()->app_FFWD_STEP;
  	$this->state->setField("grid_page_no", $this->state->getField("grid_page_no") + $step);
     if($this->state->getField("grid_page_no") > ($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)
     { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)) );//?????????????????????????????????????????
     }
  }

  public function grid_FBWD($evt)
  { $step = config::getInstance()->app_FFWD_STEP;
    $this->state->setField("grid_page_no", $this->state->getField("grid_page_no") - $step);
     if($this->state->getField("grid_page_no") < 0)
     { $this->state->setField("grid_page_no", 0);
     }
  }
  public function grid_filter($evt)
  { $this->state->setField("grid_page_no", 0);
    foreach ($evt as $key => $value)
    { if(!in_array($key, $this->not_filter))
      { if($value)
        { $this->state->setField("filter_" . $key, $value);
        } else
        { $this->state->removeField("filter_" . $key);
        }
      }
    }
  }

	public function fillXML($options = GRID_FILL_ALL, $table_name = "__table__")// $fillTable = true, $fillVariables = true, $setFilter2DS = true)
	{	$cfg           = config::getInstance();
		$afWh          = null;
		$first_row     = 0;
		$last_row      = 0;

    if(($options & GRID_FETCH_ALL) == GRID_FETCH_ALL)
    { $this->fetchType = GRID_FETCH_ALL;
    } else if(($options & GRID_FETCH_PAGED) == GRID_FETCH_PAGED)
    { $this->fetchType = GRID_FETCH_PAGED;
    }

		if(is_array($this->DAORow))
    { $this->__numRows = count($this->DAORow);
    }
		if(($this->fetchType & GRID_FETCH_PAGED) == GRID_FETCH_PAGED)
	  { if($this->state->getField("grid_page_no") > ($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)
      { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)) );
      }
	    $first_row  = (int)$this->state->getField("grid_page_no") * $cfg->app_GRID_STEP + 1;
      $last_row   = ($this->state->getField("grid_page_no") + 1)* $cfg->app_GRID_STEP;
      if($this->afterWhere)
      { $afWh = clone $this->afterWhere;
      }
      if(is_array($this->DAORow))
	    { $new_arr = array();
	    	if($this->state->getField("grid_order_field"))
	      { //print_r($this->DAORow);
	        usort($this->DAORow, array("self", "sortArray"));
	      }
	      $i = 0;
        foreach($this->DAORow as $row)
        { if($i >= $first_row - 1 && $i < $last_row)
          { $new_arr[] = $row;
          }
          $i++;
        }
	    } else
	    { if($this->state->getField("grid_order_field"))
        { $afWh->text .= " ORDER BY " . filter_var($this->state->getField("grid_order_field") . " " . $this->state->getField("SQLOrder"),
                                              FILTER_VALIDATE_REGEXP, array("options" =>array("regexp" => "/([a-z]|[A-Z]|[0-9]|_)*/")));
        }
	    }
	  }

		if(is_subclass_of($this->DAORow, "bee\DAO"))
		{ $DR = clone $this->DAORow;
  	  $rs = new rowSet($DR, $afWh, (int)$this->state->getField("grid_page_no") * $cfg->app_GRID_STEP + 1, ($this->state->getField("grid_page_no") + 1)* $cfg->app_GRID_STEP,$s);
      $this->__numRows = $rs->num_rows;

		  if($this->state->getField("grid_page_no") > ($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)
      { $this->state->setField("grid_page_no", ( (int)(floor($this->__numRows - 1) / config::getInstance()->app_GRID_STEP)) );
        $first_row  = (int)$this->state->getField("grid_page_no") * $cfg->app_GRID_STEP + 1;
        $last_row   = ($this->state->getField("grid_page_no") + 1)* $cfg->app_GRID_STEP;
        $rs = new rowSet($DR, $afWh, (int)$this->state->getField("grid_page_no") * $cfg->app_GRID_STEP + 1, ($this->state->getField("grid_page_no") + 1)* $cfg->app_GRID_STEP,$s);
      }
		}

		if(($options & GRID_FILL_TABLE) == GRID_FILL_TABLE)
		{ if(is_array($this->DAORow))
      { $DSDoc->setTableFromArr(isset($new_arr) ? $new_arr : $this->DAORow, $table_name, $this->foreignKeys);
      } else if(is_subclass_of($this->DAORow, "bee\DAO"))
      { static::$DSDoc->setTable($rs, $rs->getTableName(),$this->foreignKeys);
      }
    }

		if(($options & GRID_FILL_VARIABLES) == GRID_FILL_VARIABLES)
		{	static::$DSDoc->setVariable("grid_order", $this->state->getField("grid_order") ?: "ascending");
		  static::$DSDoc->setVariable("grid_anti_order", ($this->state->getField("grid_order") == "descending")? "ascending": "descending");
			static::$DSDoc->setVariable("grid_order_field", $this->state->getField("grid_order_field") ?: "");
			static::$DSDoc->setVariable("grid_order_type", $this->state->getField("grid_order_type") ?: "text");
			static::$DSDoc->setVariable("grid_page_no", $this->state->getField("grid_page_no") ?: 0);

			static::$DSDoc->setVariable("app_grid_step", $cfg->app_GRID_STEP);
			static::$DSDoc->setVariable("app_FFWD_STEP", $cfg->app_FFWD_STEP);
			/**
			 * @todo riješiti se jednog od donja 2
			 */
			static::$DSDoc->setVariable("grid_total_rows", $this->__numRows);
			static::$DSDoc->setVariable("grid_num_rows", $this->__numRows);
		}

		if(($options & GRID_FILL_FILTER) == GRID_FILL_FILTER)
    { foreach($this->state->arr_val as $key => $value)
      { //echo "$key<br />";
      	if(substr($key, 0, 7) == "filter_")
        { static::$DSDoc->setVariable( $key, $value);

        }
      }
    }
	}
	/**
	 *
	 * @param array $e1
	 * @param array $e2
	 * @return int
	 */
	private function sortArray($e1, $e2)
	{ $sort_type = $this->state->getField("grid_order_type") ?: "text";
		if($field = $this->state->getField("grid_order_field"))
	  { if(isset($this->foreignKeys[$field]))
	    {  $e1[$field] = isset($this->foreignKeys[$field][$e1[$field]]) ? $this->foreignKeys[$field][$e1[$field]] : "*";
	       $e2[$field] = isset($this->foreignKeys[$field][$e2[$field]]) ? $this->foreignKeys[$field][$e2[$field]] : "*";
	    }

	  	if(strcmp($e1[$field], $e2[$field]) < 0 && $sort_type == "text" || (int)$e1[$field] < (int)$e2[$field] && $sort_type == "number")
	    { if(($this->state->getField("SQLOrder") ?: "ASC") == "ASC")
	      { $return = -1;
	      } else
	      { $return = 1;
	      }
	    } else if(strcmp($e1[$field], $e2[$field]) > 0 && $sort_type == "text" || (int)$e1[$field] > (int)$e2[$field] && $sort_type == "number")
	    { if(($this->state->getField("SQLOrder") ?: "ASC") == "ASC")
        { $return = 1;
        } else
        { $return = -1;
        }
	    } else
	    { $return = 0;
	    }
	  } else
	  { $return = 0;
	  }
	  return $return;
	}

  private function filterArray($value)
  { $sort_type = $this->state->getField("grid_order_type") ?: "text";
    if($field = $this->state->getField("grid_order_field"))
    { if(isset($this->foreignKeys[$field]))
      { $e1[$field] = isset($this->foreignKeys[$field][$e1[$field]]) ? $this->foreignKeys[$field][$e1[$field]] : "*";
        $e2[$field] = isset($this->foreignKeys[$field][$e2[$field]]) ? $this->foreignKeys[$field][$e2[$field]] : "*";
      }
      if(($e1[$field] < $e2[$field] && $sort_type == "text") || (int)$e1[$field] < (int)$e2[$field])
      { if(($this->state->getField("SQLOrder") ?: "ASC") == "ASC")
        { return -1;
        } else
        { return 1;
        }
      } else if(($e1[$field] > $e2[$field] && $sort_type == "text") || (int)$e1[$field] > (int)$e2[$field])
      { if(($this->state->getField("SQLOrder") ?: "ASC") == "ASC")
        { return 1;
        } else
        { return -1;
        }
      } else
      { return 0;
      }
    } else
    { return 0;
    }
  }
}
